package Gobang;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 

public class GamePanel extends JPanel implements MouseListener,MouseMotionListener,ActionListener
{
	private static final long serialVersionUID = -7450693911538496165L;
 
	/** 游戏逻辑 */
	private GameLogic gameLogic;
 
	/** 格子大小 */
	final int spaceSize = 40;
 
	/** 棋子大小（直径） */
	final int chessSize = 30;
 
	/** 棋盘X方向格数 */
	final int chessBoradXGrids = 15;
 
	/** 棋盘Y方向格数 */
	final int chessBoradYGrids = 15;
 
	/** 棋盘左上角X坐标 */
	final int chessBoradX = 30;
 
	/** 棋盘左上角Y坐标 */
	final int chessBoradY = 30;
	
	/** 棋盘宽度 */
	final int chessBoradWidth = spaceSize * (chessBoradXGrids - 1);
 
	/** 棋盘高度 */
	final int chessBoradHeight = spaceSize * (chessBoradYGrids - 1);
	
	/** 黑棋标识 */
	final int BLACKCHESS = 1;
 
	/** 白棋标识 */
	final int WHITECHESS = 2;
			
	/** 对战方式（0-人机对战，1-人人对战） */
	int fightType ;
 
	/** 先手选择（0-玩家先手，1-电脑先手） */
	int playFirst ;
 
	/** 黑白选择（0-玩家执黑，1-玩家执白） */
	int chessColor ;
	
	/** 电脑棋子颜色 */
	int computerChess = -1 ;
	
	/** 玩家棋子颜色 */
	int playerChess = -1 ;
	
	/** 白棋悔棋数 */
	int whiteUndoNum = 3;
	
	/** 黑棋悔棋数 */
	int blackUndoNum = 3;
	
	/** 全部下棋信息 */
	List<Map<String,Integer>> listChess = new ArrayList<Map<String,Integer>>();
 
	/** 白棋下棋信息 */
	List<Map<String,Integer>> listChessWhite = new ArrayList<Map<String,Integer>>();
	
	/** 黑棋下棋信息 */
	List<Map<String,Integer>> listChessBlack = new ArrayList<Map<String,Integer>>();
 
	/** 胜利下棋信息（胜利后要将五子成线的那五个棋子用红线连在一起显示） */
	List<Map<String,Integer>> listChessWin = new ArrayList<Map<String,Integer>>();
 
	/** 落子指示器 */
	Map<String,Integer> mapPointer = new HashMap<String,Integer>();
	
	/** 判断游戏是否结束（true-结束，false-未结束） */
	boolean isGameOver = true;
	
	/** 组合框控件 */
	private JComboBox<String> jcb_fightType,jcb_playFirst,jcb_chessColor;
 
	/** 按钮控件 */
	private JButton jb_new,jb_undo,jb_surrender;
	
	/** 标签控件 */
	JLabel jlb_blackUndoText,jlb_blackStateText,jlb_whiteUndoText,jlb_whiteStateText;
 
	/**
	 * 功能：构造函数<br>
	 */
	public GamePanel()
	{
		//与主窗口大小保持一致，并设置背景色（去掉菜单高度）
		this.setSize(760,620);
		this.setBackground(new Color(209,146,17));
 
		//右边功能区布局
		this.option();
		
		//鼠标点击与移动监听
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		
		//游戏逻辑
		this.gameLogic = new GameLogic(this);
 
		//初始化游戏
		this.initGame();
 
	}
	
	/**
	 * 功能：右边功能区布局<br>
	 */
	private void option()
	{
		this.setLayout(null);
		//对战方式
		JLabel jlb_fightType = new JLabel("对战方式：");
		jlb_fightType.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_fightType.setForeground(Color.WHITE);
		jlb_fightType.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY,100,24);
		this.add(jlb_fightType);
		this.jcb_fightType = new JComboBox<String>(new String[]{"人机对战","人人对战"});
		this.jcb_fightType.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jcb_fightType.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 30,100,24);
		this.add(this.jcb_fightType);
		//谁先手
		JLabel jlb_playFirst = new JLabel("先手选择：");
		jlb_playFirst.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 70,100,24);
		jlb_playFirst.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_playFirst.setForeground(Color.WHITE);
		this.add(jlb_playFirst);
		this.jcb_playFirst = new JComboBox<String>(new String[]{"玩家先手","电脑先手"});
		this.jcb_playFirst.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jcb_playFirst.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 100,100,24);
		this.add(this.jcb_playFirst);
		//谁执黑
		JLabel jlb_chessColor = new JLabel("黑白选择：");
		jlb_chessColor.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 140,100,24);
		jlb_chessColor.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_chessColor.setForeground(Color.WHITE);
		this.add(jlb_chessColor);
		this.jcb_chessColor = new JComboBox<String>(new String[]{"玩家执黑","玩家执白"});
		this.jcb_chessColor.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jcb_chessColor.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 170,100,24);
		this.add(this.jcb_chessColor);
		//按钮
		this.jb_new = new JButton("开始游戏");
		this.jb_new.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jb_new.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 230,100,30);
		this.jb_new.setActionCommand("newGame");
		this.jb_new.addActionListener(this);
		this.add(this.jb_new);
		this.jb_undo = new JButton("我要悔棋");
		this.jb_undo.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jb_undo.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 280,100,30);
		this.jb_undo.setActionCommand("undo");
		this.jb_undo.addActionListener(this);
		this.jb_undo.setEnabled(false);
		this.add(this.jb_undo);
		this.jb_surrender = new JButton("我认输了");
		this.jb_surrender.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jb_surrender.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 330,100,30);
		this.jb_surrender.setActionCommand("surrender");
		this.jb_surrender.addActionListener(this);
		this.jb_surrender.setEnabled(false);
		this.add(this.jb_surrender);
		//黑棋提示
		JPanel groupBoxBlack = new JPanel();
		groupBoxBlack.setLayout(null);
		groupBoxBlack.setBackground(this.getBackground());
		groupBoxBlack.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 380,100,80);
		groupBoxBlack.setBorder(BorderFactory.createTitledBorder("黑棋"));
		this.add(groupBoxBlack);
		JLabel jlb_blackUndo = new JLabel("悔棋：");
		jlb_blackUndo.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_blackUndo.setForeground(Color.WHITE);
		jlb_blackUndo.setBounds(10,16,40,30);
		groupBoxBlack.add(jlb_blackUndo);
		this.jlb_blackUndoText = new JLabel("剩"+Integer.toString(this.blackUndoNum)+"次");
		this.jlb_blackUndoText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_blackUndoText.setForeground(Color.darkGray);
		this.jlb_blackUndoText.setBounds(44,16,50,30);
		groupBoxBlack.add(this.jlb_blackUndoText);
		JLabel jlb_blackState = new JLabel("状态：");
		jlb_blackState.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_blackState.setForeground(Color.WHITE);
		jlb_blackState.setBounds(10,44,40,30);
		groupBoxBlack.add(jlb_blackState);
		this.jlb_blackStateText = new JLabel("未开始");
		this.jlb_blackStateText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_blackStateText.setForeground(Color.darkGray);
		this.jlb_blackStateText.setBounds(44,44,50,30);
		groupBoxBlack.add(this.jlb_blackStateText);
		//白棋提示
		JPanel groupBoxWhite = new JPanel();
		groupBoxWhite.setLayout(null);
		groupBoxWhite.setBackground(this.getBackground());
		groupBoxWhite.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 480,100,80);
		groupBoxWhite.setBorder(BorderFactory.createTitledBorder("白棋"));
		this.add(groupBoxWhite);
		JLabel jlb_whiteUndo = new JLabel("悔棋：");
		jlb_whiteUndo.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_whiteUndo.setForeground(Color.WHITE);
		jlb_whiteUndo.setBounds(10,16,40,30);
		groupBoxWhite.add(jlb_whiteUndo);
		this.jlb_whiteUndoText = new JLabel("剩"+Integer.toString(this.whiteUndoNum)+"次");
		this.jlb_whiteUndoText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_whiteUndoText.setForeground(Color.darkGray);
		this.jlb_whiteUndoText.setBounds(44,16,50,30);
		groupBoxWhite.add(this.jlb_whiteUndoText);
		JLabel jlb_whiteState = new JLabel("状态：");
		jlb_whiteState.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_whiteState.setForeground(Color.WHITE);
		jlb_whiteState.setBounds(10,44,40,30);
		groupBoxWhite.add(jlb_whiteState);
		this.jlb_whiteStateText = new JLabel("未开始");
		this.jlb_whiteStateText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_whiteStateText.setForeground(Color.darkGray);
		this.jlb_whiteStateText.setBounds(44,44,50,30);
		groupBoxWhite.add(this.jlb_whiteStateText);
		
	}
	
	/**
	 * 功能：初始化游戏<br>
	 */
	public void initGame()
	{
		this.isGameOver = true;
		//清空下棋列表
		this.listChess.clear();
		this.listChessBlack.clear();
		this.listChessWhite.clear();
		this.listChessWin.clear();
		//落子指示器初始化
		this.mapPointer.put("x",-1);
		this.mapPointer.put("y",-1);
		this.mapPointer.put("show",0);	//0-不显示，1-显示
		//对战方式
		if("人人对战".equals(this.jcb_fightType.getSelectedItem().toString()))
		{
			this.fightType = 1;
		}
		else
		{
			this.fightType = 0;
		}
		//先手选择
		if("电脑先手".equals(this.jcb_playFirst.getSelectedItem().toString()))
		{
			this.playFirst = 1;
		}
		else
		{
			this.playFirst = 0;
		}
		//黑白选择
		if("玩家执白".equals(this.jcb_chessColor.getSelectedItem().toString()))
		{
			this.chessColor = 1;
		}
		else
		{
			this.chessColor = 0;
		}
		//电脑与玩家棋子颜色
		if(this.fightType == 0)
		{
			if(this.chessColor == 1)
			{
				this.playerChess = this.WHITECHESS;
				this.computerChess = this.BLACKCHESS;
			}
			else
			{
				this.computerChess = this.WHITECHESS;
				this.playerChess = this.BLACKCHESS;
			}
		}
		//悔棋数初始化
		this.whiteUndoNum = 3;
		this.blackUndoNum = 3;
		//设置控件状态
		this.setComponentState(false);
	}
	
	/**
	 * 功能：设置控件状态<br>
	 * 参数：true-新开局；false-未开局<br>
	 */
	public void setComponentState(boolean _flag)
	{
		if(_flag)	//新游戏已经开始了
		{
			this.jcb_fightType.setEnabled(false);
			this.jcb_playFirst.setEnabled(false);
			this.jcb_chessColor.setEnabled(false);
			this.jb_new.setEnabled(false);
			this.jb_undo.setEnabled(true);
			this.jb_surrender.setEnabled(true);
		}
		else	//新游戏还未开始
		{
			this.jcb_fightType.setEnabled(true);
			this.jcb_playFirst.setEnabled(true);
			this.jcb_chessColor.setEnabled(true);
			this.jb_new.setEnabled(true);
			this.jb_undo.setEnabled(false);
			this.jb_surrender.setEnabled(false);
		}
	}
	
	/**
	 * 功能：绘图<br>
	 */
	@Override
	public void paint(Graphics g)
	{
		//调用父类,让其做一些事前的工作，如刷新屏幕等
		super.paint(g);
 
		//清屏
		g.setColor(this.getBackground());
		g.fillRect(this.chessBoradX,this.chessBoradY,this.chessBoradWidth,this.chessBoradHeight);
		
		//因为要画一些特殊效果，所以要用Graphics2D
		Graphics2D g2D = (Graphics2D)g;
 
		//开始画棋盘（五子棋盘由15条横线与15条竖线交叉形成，共225个点）
		//String[] tip = {" 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9","10","11","12","13","14"};	//横竖线的坐标，有利于编程是查看定位
		g2D.setColor(Color.BLACK);
		g.setFont(new Font("微软雅黑",Font.PLAIN,14));
		for(int i=0;i<this.chessBoradXGrids;i++)
		{
			g2D.drawLine(this.chessBoradX,this.chessBoradY + i * this.spaceSize,this.chessBoradX + this.chessBoradWidth,this.chessBoradY + i * this.spaceSize);
			g2D.drawLine(this.chessBoradX + i * this.spaceSize,this.chessBoradY,this.chessBoradX + i * this.spaceSize,this.chessBoradY + this.chessBoradHeight);
			//g2D.drawString(tip[i],this.chessBoradX - 20,this.chessBoradY + 4 + i * this.spaceSize);
			//g2D.drawString(tip[i],this.chessBoradX - 2 + i * this.spaceSize,this.chessBoradY - 10);
		}
 
		//画5个定位点
		g2D.fillArc(this.chessBoradX + 3 * this.spaceSize - 4,this.chessBoradY + 3 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 11 * this.spaceSize - 4,this.chessBoradY + 3 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 7 * this.spaceSize - 4,this.chessBoradY + 7 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 3 * this.spaceSize - 4,this.chessBoradY + 11 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 11 * this.spaceSize - 4,this.chessBoradY + 11 * this.spaceSize - 4,8,8,0,360);
		
		//画落子指示器
		if(this.mapPointer.get("show") == 1)
		{
			g2D.setColor(Color.RED);
			g2D.setStroke(new BasicStroke(2.5f));
			//先以交叉点为中心取到指示器周围的4个角坐标
			//中心点坐标
			int x = this.chessBoradX + this.mapPointer.get("x") * this.spaceSize;
			int y = this.chessBoradY + this.mapPointer.get("y") * this.spaceSize;
			//左上角坐标，并向下向右画线
			int x1 = x - this.chessSize / 2;
			int y1 = y - this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 + this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 + this.chessSize / 4,y1);
			//右上角坐标，并向下向左画线
			x1 = x + this.chessSize / 2;
			y1 = y - this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 + this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 - this.chessSize / 4,y1);
			//左下角坐标，并向上向右画线
			x1 = x - this.chessSize / 2;
			y1 = y + this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 - this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 + this.chessSize / 4,y1);
			//右下角坐标，并向上向左画线
			x1 = x + this.chessSize / 2;
			y1 = y + this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 - this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 - this.chessSize / 4,y1);
			//System.out.println("("+this.mapPointer.get("x")+","+this.mapPointer.get("y")+")");
		}
 
		//画棋子（就是一个黑色的圆，里面在接近圆心的位置上画一个由白到黑的渐变内圆）
		for(int i=0;i<this.listChess.size();i++)
		{
			Map<String,Integer> map = this.listChess.get(i);
        	int lineX = map.get("x");
        	int lineY = map.get("y");
        	int flag = map.get("flag");
        	//将垂直与水平线的数目转化为像素
        	int x = this.chessBoradX + lineX * this.spaceSize;
        	int y = this.chessBoradY + lineY  * this.spaceSize;
    		//做一个由白到黑渐变的圆绘画
        	RadialGradientPaint paint = null;
        	if(flag == this.WHITECHESS)
        	{
        		paint = new RadialGradientPaint(x + 5,y + 5,90, new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
        	}
        	else
        	{
        		paint = new RadialGradientPaint(x + 3,y + 3,10, new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
        	}
    		g2D.setPaint(paint);
    		//着色微调
    		g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);	//消除画图锯齿
    		g2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);		//追求速度或质量
    		//画圆，里面套一个白到黑渐变的圆
    		Ellipse2D e = new Ellipse2D.Float(x - this.chessSize/2,y - this.chessSize/2,this.chessSize,this.chessSize);
    		g2D.fill(e);
    		//标记最后一个棋子的红矩形框
    		if(i == this.listChess.size() - 1)
    		{
    			g2D.setColor(Color.RED);
    			g2D.setStroke(new BasicStroke(2.5f));
    			g2D.drawRect(x - 5,y - 5,10,10);
    		}
		}
		
		//画五子成线
		if(this.listChessWin.size() > 4)
		{
			g2D.setColor(Color.RED);
			g2D.setStroke(new BasicStroke(2.5f));
			int x1 = 0;
			int y1 = 0;
			for(int i=0;i<this.listChessWin.size();i++)
			{
				Map<String,Integer> map = this.listChessWin.get(i);
				if(i == 0)	//先得到第一个点
				{
					x1 = map.get("x");
					y1 = map.get("y");
				}
				else	//再用第一个点与其他的点连线
				{
					g2D.drawLine(this.chessBoradX + x1 * this.spaceSize,this.chessBoradY + y1 * this.spaceSize,this.chessBoradX + map.get("x") * this.spaceSize,this.chessBoradY +map.get("y") * this.spaceSize);
				}
			}
		}
		
	}
	
	/**
	 * 功能：开始新游戏<br>
	 */
	public void newGame()
	{
		//初始化游戏
		this.initGame();
		//设置控件状态
		this.setComponentState(true);
		//设置游戏结束标识
		this.isGameOver = false;
		//电脑先手
		if(this.fightType == 0 && this.playFirst == 1)
		{
			this.gameLogic.computerPlay();
		}
		
	}
	
	/**
	 * 功能：悔棋<br>
	 */
	public void undo()
	{
		if(this.gameLogic.undo()){this.repaint();}
	}
 
	/**
	 * 功能：投降<br>
	 */
	public void surrender()
	{
		if(this.isGameOver){return;}
		JOptionPane.showMessageDialog(null,"啥，认输了，还能再有点出息不！");
		this.isGameOver = true;
		this.setComponentState(false);
		this.jlb_blackStateText.setText("已结束");
		this.jlb_whiteStateText.setText("已结束");
	}
	
	/**
	 * 功能：鼠标移动监听<br>
	 */
	@Override
	public void mouseMoved(MouseEvent e)
	{
		this.gameLogic.mouseMoved(e);
	}
	
	/**
	 * 功能：鼠标单击监听<br>
	 */
	@Override
	public void mouseClicked(MouseEvent e) 
	{
		this.gameLogic.mouseClicked(e);
	}
	
	/**
	 * 功能：功能监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		
		if("newGame".equals(command))
		{
			this.newGame();
		}
		else if("undo".equals(command))
		{
			this.undo();
		}
		else if("surrender".equals(command))
		{
			this.surrender();
		}
		
	}
 
	@Override
	public void mousePressed(MouseEvent e) {}
 
	@Override
	public void mouseReleased(MouseEvent e) {}
 
	@Override
	public void mouseEntered(MouseEvent e) {}
 
	@Override
	public void mouseExited(MouseEvent e) {}
 
	@Override
	public void mouseDragged(MouseEvent e) {}
 
}